package com.zzyl.nursing.service.impl;

import java.time.LocalTime;
import java.util.*;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.zzyl.common.constant.CacheConstants;
import com.zzyl.common.utils.DateUtils;
import com.zzyl.nursing.domain.AlertData;
import com.zzyl.nursing.domain.DeviceData;
import com.zzyl.nursing.mapper.DeviceMapper;
import com.zzyl.nursing.service.IAlertDataService;
import com.zzyl.system.mapper.SysUserRoleMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.zzyl.nursing.mapper.AlertRuleMapper;
import com.zzyl.nursing.domain.AlertRule;
import com.zzyl.nursing.service.IAlertRuleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import java.util.concurrent.TimeUnit;

/**
 * 报警规则Service业务层处理
 *
 * @author ruoyi
 * @date 2024-12-18
 */
@Service
@Slf4j
public class AlertRuleServiceImpl extends ServiceImpl<AlertRuleMapper, AlertRule> implements IAlertRuleService {
    @Autowired
    private AlertRuleMapper alertRuleMapper;

    /**
     * 查询报警规则
     *
     * @param id 报警规则主键
     * @return 报警规则
     */
    @Override
    public AlertRule selectAlertRuleById(Long id) {
        return getById(id);
    }

    /**
     * 查询报警规则列表
     *
     * @param alertRule 报警规则
     * @return 报警规则
     */
    @Override
    public List<AlertRule> selectAlertRuleList(AlertRule alertRule) {
        return alertRuleMapper.selectAlertRuleList(alertRule);
    }

    /**
     * 新增报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int insertAlertRule(AlertRule alertRule) {
        return save(alertRule) ? 1 : 0;
    }

    /**
     * 修改报警规则
     *
     * @param alertRule 报警规则
     * @return 结果
     */
    @Override
    public int updateAlertRule(AlertRule alertRule) {
        return updateById(alertRule) ? 1 : 0;
    }

    /**
     * 批量删除报警规则
     *
     * @param ids 需要删除的报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleByIds(Long[] ids) {
        return removeByIds(Arrays.asList(ids)) ? 1 : 0;
    }

    /**
     * 删除报警规则信息
     *
     * @param id 报警规则主键
     * @return 结果
     */
    @Override
    public int deleteAlertRuleById(Long id) {
        return removeById(id) ? 1 : 0;
    }

    @Autowired
    private RedisTemplate redisTemplate;

    @Override
    public void alertFilter() {
        //查询报警规则数量根据状态
        long count = count(Wrappers.<AlertRule>lambdaQuery().eq(AlertRule::getStatus, 1));
        if (count == 0) {
            return;
        }
        //从redis中获取所有上报数据
        List list = redisTemplate.opsForHash().values(CacheConstants.IOT_DEVICE_DATA_LATEST);
        if (CollUtil.isEmpty(list)) {
            return;
        }
        List<DeviceData> deviceDataList = new ArrayList<>();
        list.forEach(v -> deviceDataList.addAll(JSONUtil.toList(v.toString(), DeviceData.class)));

        //4.遍历数据，执行是否满足报警规则
        deviceDataList.forEach(deviceData -> {
            alertDataFilter(deviceData);
        });


    }

    @Autowired
    private IAlertRuleService alertRuleService;

    private void alertDataFilter(DeviceData deviceData) {
        //1.准备对应的报警规则数据
        //全部设备规则
        LambdaQueryWrapper<AlertRule> queryWrapper = Wrappers.<AlertRule>lambdaQuery()
                .eq(AlertRule::getProductKey, deviceData.getProductKey())
                .eq(AlertRule::getFunctionId, deviceData.getFunctionId())
                .eq(AlertRule::getStatus, 1)
                .and(wrapper -> wrapper.eq(AlertRule::getIotId, deviceData.getIotId())
                        .or().eq(AlertRule::getIotId, "-1"));

        List<AlertRule> allRuleList = alertRuleService.list(queryWrapper);

        if (CollectionUtils.isEmpty(allRuleList)) {
            return;
        }
        //2.遍历规则，判断是否满足报警规则
        allRuleList.forEach(alertRule -> {
            deviceDataAlarmHandler(alertRule, deviceData);
        });

    }


    private void deviceDataAlarmHandler(AlertRule alertRule, DeviceData deviceData) {
        String iotId = deviceData.getIotId();
        //取出对应的报警规则
        if (!alertRule.getFunctionId().equals(deviceData.getFunctionId())) {
            return;
        }
        //判断是否在生效时间
        String[] split = alertRule.getAlertEffectivePeriod().split("~");
        LocalTime startTime = LocalTime.parse(split[0]);
        LocalTime endTime = LocalTime.parse(split[1]);
        LocalTime time = deviceData.getAlarmTime().toLocalTime();
        if (time.isBefore(startTime) || time.isAfter(endTime)) {
            return;
        }
        Double value = alertRule.getValue();
        String operator = alertRule.getOperator();
        Double v = Double.valueOf(deviceData.getDataValue());
        //实用工具类判断
        int compare = NumberUtil.compare(v, value);
        //根据结果判断是否满足报警规则
        if (compare >= 0 && operator.equals(">=") || compare < 0 && operator.equals("<")) {
            log.info("报警规则：{}，设备：{}，数据：{} 发出警告", alertRule.getId(), deviceData.getIotId(), deviceData.getDataValue());
        } else {
            //删除报警数
            return;
        }
        //判断是否在沉默周期
        JudgmentSilencePeriod(iotId, deviceData, alertRule);


    }

    private void JudgmentSilencePeriod(String iotId, DeviceData deviceData, AlertRule alertRule) {
        String aggCountKey = CacheConstants.ALERT_TRIGGER_COUNT_PREFIX + iotId + ":" + deviceData.getFunctionId() + ":" + alertRule.getId();
        String s = CacheConstants.AlERT_SILENT_PREFIX + iotId + ":" + deviceData.getFunctionId();
        String alertSilentData = (String) redisTemplate.opsForValue().get(s);
        if (!ObjectUtil.isEmpty(alertSilentData)) {
            return;
        }
        //查询报警次数
        Integer aggCountData = (Integer) redisTemplate.opsForValue().get(aggCountKey);
        Integer alertCount = ObjectUtil.isEmpty(aggCountData) ? 0 : aggCountData + 1;
        if (ObjectUtil.notEqual(alertCount, alertRule.getDuration())) {
            redisTemplate.opsForValue().set(aggCountKey, alertCount);
            return;
        }
        //发出报警删除劲爆次数添加沉默周期
        redisTemplate.delete(aggCountKey);
        redisTemplate.opsForValue().set(s, "超级侦探，认真办案", alertRule.getAlertSilentPeriod(), TimeUnit.MINUTES);
        EnquiryNotifier(alertRule, iotId, deviceData);
    }

    @Autowired
    private DeviceMapper deviceMapper;
    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;
    //维修工
    @Value("${alert.deviceMaintainerRole}")
    private String deviceMaintainerRole;
    //管理员
    @Value("${alert.managerRole}")
    private String managerRole;

    private void EnquiryNotifier(AlertRule alertRule, String iotId, DeviceData deviceData) {
        Integer alertDataType = alertRule.getAlertDataType();
        List<Long> userId = null;
        if (alertDataType.equals(0)) {
            //老人异常数据,添加老人护工的id

            if (deviceData.getLocationType().equals(0)) {
                userId = deviceMapper.selectNursingIdsByIotIdWithElder(iotId);
            } else if (deviceData.getLocationType().equals(1) && deviceData.getPhysicalLocationType() == 2) {
                userId = deviceMapper.selectNursingIdsByIotIdWithBed(iotId);
            }
        } else if (alertDataType.equals(1)) {
            //其他异常数据
            userId = sysUserRoleMapper.selectUserIdByRoleName(iotId);
        }
        //获取管理员id
        List<Long> managerUserIds = sysUserRoleMapper.selectUserIdByRoleName(managerRole);
        //合并用户id
        Collection<Long> allUserIds = CollUtil.addAll(userId, managerUserIds);
        //合并之后与可能有重复id,去重
        allUserIds = CollUtil.distinct(allUserIds);

        //批量保存报警数据到alert_data表中
        insertAlertData(allUserIds, alertRule, deviceData);
    }

    @Autowired
    private IAlertDataService alertDataService;

    private void insertAlertData(Collection<Long> allUserIds, AlertRule alertRule, DeviceData deviceData) {
        List<AlertData> list = new ArrayList();
        // 遍历allUserIds
        allUserIds.forEach(userId -> {
            // 对象拷贝
            AlertData alertData = BeanUtil.toBean(deviceData, AlertData.class);
            alertData.setAlertRuleId(alertRule.getId());
            // 心率<60,持续3个周期就报警
            String alertReason = CharSequenceUtil.format("{}{}{},持续{}个周期就报警", alertRule.getFunctionName(), alertRule.getOperator(), alertRule.getValue(), alertRule.getDuration());
            alertData.setAlertReason(alertReason);
            alertData.setStatus(0);
            alertData.setType(alertRule.getAlertDataType());
            alertData.setUserId(userId);
            alertData.setId(null);
            list.add(alertData);
        });

        alertDataService.saveBatch(list);
    }
}
